#pragma once

namespace shijie
{
	namespace utility
	{
		template <typename T>
		class UniquePtr
		{
		public:
			UniquePtr() : m_data(nullptr) {}
			UniquePtr(T *data) : m_data(data){}
			UniquePtr(const UniquePtr<T> &other) = delete;
			UniquePtr(UniquePtr<T> &&other) : m_data(other.release()) {}
			~UniquePtr() {
				if (m_data != nullptr) {
					delete m_data;
					m_data = nullptr;
				}
			}

			T *get() {
				return m_data;
			}

			T *release() { // 返回一个指针，同时自己不再占用指针
				auto data = m_data;
				m_data = nullptr;
				return data;
			}

			void reset(T *data = nullptr) {
				if (m_data != data) {
					delete m_data;
					m_data = data;
				}
			}

			void swap(UniquePtr<T>& other) {
				auto data = other.m_data;
				other.m_data = m_data;
				m_data = data;
			} 

			T * operator->() {
				return m_data;
			}

			T & operator * () {
				return *m_data;
			}
		
			UniquePtr & operator = (const UniquePtr<T> &other) = delete {}
			UniquePtr & operator = (UniquePtr<T>&& other) {
				if (this == &other) {
					return *this;
				}
				reset(other.release());
				return *this;
			}

			T & operator[](int i) const {
				return m_data[i];
			}

			explicit operator bool() const noexcept {
				return m_data != nullptr;
			}


		private:
		 	T * m_data;
		};
	}
}